"""
事务管理服务
============

提供数据库事务管理功能，确保多表操作的原子性
"""

from contextlib import asynccontextmanager
from typing import AsyncGenerator, Callable
from sqlalchemy.ext.asyncio import AsyncSession

from redfire_framework.core.exceptions import DatabaseTransactionError


class TransactionService:
    """事务管理服务类"""
    
    def __init__(self, session_factory):
        """
        初始化事务服务
        
        Args:
            session_factory: DatabaseManager的get_session方法（异步上下文管理器）
        """
        self.session_factory = session_factory
    
    @asynccontextmanager
    async def transaction(self) -> AsyncGenerator[AsyncSession, None]:
        """
        事务上下文管理器
        
        提供原子性保证：
        - 成功时自动提交
        - 异常时自动回滚
        - 确保资源正确释放
        
        Usage:
            async with transaction_service.transaction() as session:
                # 执行多个数据库操作
                user = await user_repo.create_with_session(session, user_data)
                profile = await profile_repo.create_with_session(session, profile_data)
                # 如果任何操作失败，整个事务会回滚
        """
        # session_factory是一个异步上下文管理器，需要用async with
        async with self.session_factory() as session:
            try:
                # 开始事务
                async with session.begin():
                    # 提供会话给调用者
                    yield session
                    # 如果没有异常，事务会自动提交
                    
            except Exception as e:
                # 异常会自动触发回滚
                raise DatabaseTransactionError(
                    f"Transaction failed and was rolled back: {str(e)}"
                ) from e
    
    async def execute_in_transaction(self, operations: list) -> list:
        """
        在事务中执行多个操作
        
        Args:
            operations: 操作列表，每个操作是一个异步函数
            
        Returns:
            所有操作的结果列表
            
        Raises:
            DatabaseTransactionError: 当任何操作失败时
        """
        async with self.transaction() as session:
            results = []
            for operation in operations:
                result = await operation(session)
                results.append(result)
            return results
